/*
 * Description: createContainer - 状态管理方案
 * Author: wangyifei
 * DateCreated: 2024-02-09 14:33
 */

import { Button, Space } from 'antd';
import {
	type PropsWithChildren,
	createContext,
	useContext,
	useState,
	useRef,
	useEffect,
	useCallback
} from 'react';

type AnyObject = Record<PropertyKey, any>;
function shallowEqual(prev: AnyObject, next: AnyObject) {
	let flog = true;
	for (const key in prev) {
		flog = prev[key] === next[key];
	}
	return flog;
}

// console.log(shallowEqual({ name: 'frank' }, { name: 'frank' }));

function createContainer(useHook: any) {
	// 有状态
	const IntrinsicContext = createContext(null);
	// 无状态，下面通过 ref 来保存最新的数据
	const ObservableContext = createContext(null);

	// 用来提供数据
	const Provider = function Provider({ children }: PropsWithChildren) {
		// 通过 ref 来保存数据，不会触发组件渲染
		const { current: observableValue } = useRef({ state: null, observers: new Set<any>() });

		const state = useHook();
		// 保存最新的数据
		observableValue.state = state;

		useEffect(() => {
			observableValue.observers.forEach((observer) => observer());
		});

		return (
			<IntrinsicContext.Provider value={state}>
				<ObservableContext.Provider value={observableValue}>{children}</ObservableContext.Provider>
			</IntrinsicContext.Provider>
		);
	};

	// 消费数据
	const useContainer = function (_depCb: any) {
		const depCp = useCallback(_depCb, []);

		console.log('useContainer====');

		const observableValue = useContext(ObservableContext);
		const [state, setState] = useState(observableValue.state);
		const prevDepsRef = useRef([]);

		useEffect(() => {
			const observer = () => {
				const prev = prevDepsRef.current;
				const cur = depCp(observableValue.state);
				console.log('observableValue: ', observableValue, prev, cur);
				// 通过浅比较，来判断依赖是否有变化
				// console.log('====: ', !shallowEqual(prev, cur));
				if (!shallowEqual(prev, cur)) {
					setState(observableValue.state);
				}
				prevDepsRef.current = cur;
			};

			observableValue.observers.add(observer);

			return () => {
				observableValue.observers.delete(observer);
			};
		}, []);

		return state;
	};

	return { Provider, useContainer };
}

const { Provider, useContainer } = createContainer(() => {
	const [counter, setCounter] = useState(0);
	const [bar, setBar] = useState(10);

	return { counter, setCounter, bar, setBar };
});

const Child = () => {
	const { counter, setCounter } = useContainer((state: any) => [state.counter]);
	console.log('我是子组件');
	return <Button onClick={() => setCounter(counter + 1)}>{counter}</Button>;
};

const Brother = () => {
	const { bar, setBar } = useContainer((state: any) => [state.bar]);
	console.log('我是兄弟组件');
	return <Button onClick={() => setBar(bar + 1)}>{bar}</Button>;
};

const CreateContainer = () => {
	return (
		<Provider>
			<Space>
				<Child />
				<Brother />
			</Space>
		</Provider>
	);
};

export default CreateContainer;
